﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

using EdgeStatz.ModelEngine.FolderTools;
using EdgeStatz.ESSystems.Objects;

namespace EdgeStatz.DesignTools
{
    public partial class FolderDesigner : UserControl
    {
        #region Instance Variables
        FolderDefinition[] folders;
        EnumFolderDefinition[] enums;

        int currentIndex = -1;
        SubFolderDefinition currentSF = null;
        #endregion

        #region Initialization
        public FolderDesigner()
        {
            InitializeComponent();
            InitializeValues();
            
            string modelpath = GlobalSystemSettings.ModelFilePath;
            if (modelpath == null || modelpath == "")
                throw new NullReferenceException("File path is empty or null.");

            folders = Designer.FolderEngine.GetFolderDefinitions();
            enums = Designer.FolderEngine.GetEnumFolderDefinitions();

            RefreshFolders();
            ResetProperties();
            ResetSubFolders();
        }

        public void Save() { }

        private void InitializeValues()
        {
            string[] tables = Designer.DatabaseEngine.GetTableNames();
            cbFolderTable.Items.Clear();
            cbFolderTable.Items.AddRange(tables);

            cbFolderLevel.Items.Clear();
            cbFolderLevel.Items.AddRange(new string[] { "1", "2", "3", "4", "Enum" });
        }
        #endregion

        #region Refresh
        private void RefreshFolders()
        {
            lvFolders.Items.Clear();
            for (int i = 0; i < folders.Length; i++)
            {
                ListViewItem lvitem = new ListViewItem();
                switch (folders[i].Level)
                {
                    case FolderLevel.One:
                        lvitem.Group = lvFolders.Groups[0];
                        break;
                    case FolderLevel.Two:
                        lvitem.Group = lvFolders.Groups[1];
                        break;
                    case FolderLevel.Three:
                        lvitem.Group = lvFolders.Groups[2];
                        break;
                    case FolderLevel.Four:
                        lvitem.Group = lvFolders.Groups[3];
                        break;
                }

                lvitem.Name = folders[i].Name;
                lvitem.Text = folders[i].Name;

                lvFolders.Items.Add(lvitem);
            }
            foreach (EnumFolderDefinition efd in enums)
            {
                ListViewItem lvitem = new ListViewItem();
                lvitem.Group = lvFolders.Groups[4];
                lvitem.Name = efd.Name;
                lvitem.Text = efd.Name;
                lvFolders.Items.Add(lvitem);
            }
            currentIndex = -1;
            currentSF = null;
            ResetProperties();
            ResetSubFolders();
        }

        private void ResetProperties()
        {
            tabControl1.Enabled = false;

            tbFolderName.Enabled = true;
            cbFolderTable.Enabled = true;
            cbFolderDisplay.Enabled = true;
            tbFolderDisplayExp.Enabled = false; 
            cbFolderValue.Enabled = true;
            tbFolderValueExp.Enabled = false; 
            cbFolderLevel.Enabled = true;

            tbFolderName.Text = "";
            cbFolderTable.SelectedIndex = -1;
            cbFolderDisplay.SelectedIndex = -1;
            tbFolderDisplayExp.Text = "";
            cbFolderValue.SelectedIndex = -1;
            tbFolderValueExp.Text = ""; 
            cbFolderLevel.SelectedIndex = -1;

            currentIndex = -1;
        }

        private void ResetSubFolders()
        {
            cbSfName.Items.Clear();
            cbSfColumn.Items.Clear();

            ArrayList fnames = new ArrayList();
            foreach (FolderDefinition fdef in folders)
                fnames.Add(fdef.Name);
            cbSfName.Items.AddRange(fnames.ToArray());
        }

        private void RefreshSubFolders()
        {
            cbSfName.Enabled = false;
            cbSfColumn.Enabled = false;
            cbSfForeignCol.Enabled = false;

            tsbCancelSubFolder.Enabled = false;
            tsbSaveSubFolder.Enabled = false;

            currentSF = null;

            if (currentIndex == -1)
                return;

            if (currentIndex < folders.Length)
            {
                if (folders[currentIndex].Level == FolderLevel.Four)
                    return;

                lvSubFolders.Items.Clear();
                foreach (SubFolderDefinition sfdef in folders[currentIndex].SubFolders)
                    lvSubFolders.Items.Add(sfdef.Name);

                cbSfForeignCol.Items.Clear();
                cbSfForeignCol.Items.AddRange(
                Designer.DatabaseEngine.GetTableByName(
                folders[currentIndex].TableName).GetColumnNames());
            }
            else if (currentIndex < folders.Length + enums.Length)
                return;
            ResetSubFolders();
        }
        #endregion

        #region Folder Methods
        private void AddNewFolder(string name, string table, FolderLevel level, string display, string value)
        {
            ArrayList tempfolders = new ArrayList();
            tempfolders.AddRange(folders);
            tempfolders.Add(new FolderDefinition(name, table, level, display, value));
            folders = (FolderDefinition[])tempfolders.ToArray(typeof(FolderDefinition));
            RefreshFolders();
        }

        private void AddNewEnum(string name, string table, string display, string value)
        {
            List<EnumFolderDefinition> tempenum = new List<EnumFolderDefinition> { };
            tempenum.AddRange(enums);
            tempenum.Add(new EnumFolderDefinition(name, table, display, value));
            enums = tempenum.ToArray();
            RefreshFolders();
        }

        private void MoveFolderUp(int index)
        {
            if (index < 1 || index == folders.Length)
                return;
            if (index < folders.Length)
            {
                FolderDefinition fdef = folders[index];
                folders[index] = folders[index - 1];
                folders[index - 1] = fdef;
            }
            else if (index < folders.Length + enums.Length)
            {
                index = index - folders.Length;
                EnumFolderDefinition edef = enums[index];
                enums[index] = enums[index - 1];
                enums[index - 1] = edef;
            }
            RefreshFolders();
        }

        private void MoveFolderDown(int index)
        {
            if (index == folders.Length - 1 || index == folders.Length + enums.Length - 1)
                return;
            if (index < folders.Length)
            {
                FolderDefinition fdef = folders[index];
                folders[index] = folders[index + 1];
                folders[index + 1] = fdef;
            }
            else if (index < folders.Length + enums.Length)
            {
                index = index - folders.Length;
                EnumFolderDefinition edef = enums[index];
                enums[index] = enums[index + 1];
                enums[index + 1] = edef;
            }
            RefreshFolders();
        }

        private void RemoveFolder(int index)
        {
            if (index < folders.Length)
            {
                List<FolderDefinition> tempfolders = new List<FolderDefinition> { };
                tempfolders.AddRange(folders);
                tempfolders.RemoveAt(index);
                folders = tempfolders.ToArray();
            }
            else if (index < folders.Length + enums.Length)
            {
                List<EnumFolderDefinition> tempenums = new List<EnumFolderDefinition> { };
                tempenums.AddRange(enums);
                tempenums.RemoveAt(index - folders.Length);
                enums = tempenums.ToArray();
            }
            RefreshFolders();
        }
        #endregion

        #region Folder Event Handlers

        private void menuItemLargeIcon_Click(object sender, EventArgs e)
        { lvFolders.View = View.LargeIcon; }
        private void menuItemSmallIcon_Click(object sender, EventArgs e)
        { lvFolders.View = View.SmallIcon; }
        private void menuItemList_Click(object sender, EventArgs e)
        { lvFolders.View = View.List; }
        private void menuItemDetails_Click(object sender, EventArgs e)
        { lvFolders.View = View.Details; }

        private void tsbMoveUp_Click(object sender, EventArgs e)
        {
            if(lvFolders.SelectedIndices.Count == 1)
                MoveFolderUp(lvFolders.SelectedIndices[0]);
        }

        private void tsbMoveDown_Click(object sender, EventArgs e)
        {
            if (lvFolders.SelectedIndices.Count == 1)
                MoveFolderDown(lvFolders.SelectedIndices[0]);
        }

        private void tsbDeleteFolder_Click(object sender, EventArgs e)
        {
            if (lvFolders.SelectedIndices.Count == 1)
            {
                RemoveFolder(lvFolders.SelectedIndices[0]);
                ResetProperties();
            }
        }
        
        private void tsbAddFolder_Click(object sender, EventArgs e)
        {
            ResetProperties();
            tabControl1.Enabled = true;
            lvFolders.SelectedIndices.Clear();
        }
        
        private void lvFolders_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (lvFolders.SelectedIndices.Count != 1)
            {
                currentIndex = -1;
                return;
            }
            ResetProperties();
            tabControl1.Enabled = true;
            tabControl1.SelectedTab = tpProperties;
            
            currentIndex = lvFolders.SelectedIndices[0];
            if (currentIndex < folders.Length)
            {
                FolderDefinition fdef = folders[currentIndex];
                tbFolderName.Text = fdef.Name;
                cbFolderTable.SelectedItem = fdef.TableName;
                
                switch (fdef.Level)
                {
                    case FolderLevel.One:
                        cbFolderLevel.SelectedIndex = 0;
                        break;
                    case FolderLevel.Two:
                        cbFolderLevel.SelectedIndex = 1;
                        break;
                    case FolderLevel.Three:
                        cbFolderLevel.SelectedIndex = 2;
                        break;
                    case FolderLevel.Four:
                        cbFolderLevel.SelectedIndex = 3;
                        cbFolderDisplay.SelectedItem = -1;
                        cbFolderValue.SelectedItem = -1;
                        tbFolderDisplayExp.Text = "";
                        tbFolderValueExp.Text = "";
                        return;
                }

                if (cbFolderDisplay.Items.Contains(fdef.DisplayExp))
                    cbFolderDisplay.SelectedItem = fdef.DisplayExp;
                else
                {
                    cbFolderDisplay.SelectedIndex = 0;
                    tbFolderDisplayExp.Text = fdef.DisplayExp.StartsWith("Eval(") ? 
                        fdef.DisplayExp.Remove(0, 5).Remove(fdef.DisplayExp.Length - 6, 1) : 
                        fdef.DisplayExp;
                }

                if (cbFolderValue.Items.Contains(fdef.ValueExp))
                    cbFolderValue.SelectedItem = fdef.ValueExp.StartsWith("Eval(") ?
                        fdef.ValueExp.Remove(0, 5).Remove(fdef.ValueExp.Length - 6, 1) :
                        fdef.ValueExp;
                else
                {
                    cbFolderValue.SelectedIndex = 0;
                    tbFolderValueExp.Text = fdef.ValueExp;
                }

                lvSubFolders.Items.Clear();
                foreach (SubFolderDefinition sfdef in fdef.SubFolders)
                    lvSubFolders.Items.Add(sfdef.Name);

            }
            else if (currentIndex < folders.Length + enums.Length)
            {
                EnumFolderDefinition edef = enums[currentIndex - folders.Length];
                tbFolderName.Text = edef.Name;
                cbFolderTable.SelectedItem = edef.TableName;
                cbFolderDisplay.SelectedItem = edef.DisplayExp;
                cbFolderValue.SelectedItem = edef.ValueExp;
                
                tbFolderDisplayExp.Text = "";
                tbFolderValueExp.Text = "";
                cbFolderLevel.SelectedIndex = 4;
            }
        }

        private void cbFolderTable_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (cbFolderTable.SelectedItem == null)
                return;
            TableDefinition tdef = Designer.DatabaseEngine.GetTableByName(cbFolderTable.SelectedItem.ToString());

            cbFolderDisplay.SelectedIndex = -1;
            cbFolderValue.SelectedIndex = -1;
            cbFolderDisplay.Items.Clear();
            cbFolderValue.Items.Clear();
            cbFolderDisplay.Items.Add("Expression...");
            cbFolderValue.Items.Add("Expression...");
            foreach (ColumnDefinition cdef in tdef.ColumnArray)
            {    
                cbFolderDisplay.Items.Add(cdef.Name);
                cbFolderValue.Items.Add(cdef.Name);
            }
        }
                
        private void cbFolderDisplay_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (cbFolderLevel.SelectedIndex == 4)
            {
                cbFolderDisplay.SelectedIndex = -1;
                MessageBox.Show("Cannot use expressions for enums", "Designer", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }
            if (cbFolderDisplay.SelectedItem == null)
            {
                tbFolderDisplayExp.Enabled = false;
                return;
            }
            if (cbFolderDisplay.SelectedItem.ToString().Equals("Expression..."))
                tbFolderDisplayExp.Enabled = true;
            else
                tbFolderDisplayExp.Enabled = false;
        }

        private void cbFolderValue_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (cbFolderLevel.SelectedIndex == 4)
            {
                cbFolderValue.SelectedIndex = -1;
                MessageBox.Show("Cannot use expressions for enums", "Designer", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }
            if (cbFolderValue.SelectedItem == null)
            {
                tbFolderValueExp.Enabled = false;
                return;
            }
            if (cbFolderValue.SelectedItem.ToString().Equals("Expression..."))
                tbFolderValueExp.Enabled = true;
            else
                tbFolderValueExp.Enabled = false;
        }

        private void cbFolderLevel_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (cbFolderLevel.SelectedIndex > -1 && cbFolderLevel.SelectedIndex < 3)
            {
                cbFolderDisplay.Enabled = true;
                cbFolderValue.Enabled = true;
                cbFolderDisplay_SelectedIndexChanged(sender, e);
                cbFolderValue_SelectedIndexChanged(sender, e);
            }
            else if (cbFolderLevel.SelectedIndex == 3)
            {
                cbFolderDisplay.Enabled = false;
                cbFolderValue.Enabled = false;
                tbFolderDisplayExp.Enabled = false;
                tbFolderValueExp.Enabled = false;
            }
            else if (cbFolderLevel.SelectedIndex == 4)
            {
                cbFolderDisplay.Enabled = true;
                cbFolderValue.Enabled = true;
                tbFolderDisplayExp.Enabled = false;
                tbFolderValueExp.Enabled = false;
            }
        }
        
        private void tsbSaveFolder_Click(object sender, EventArgs e)
        {
            if (currentIndex == -1)
            {
                if (cbFolderLevel.SelectedIndex == 4)
                {
                    ArrayList tmpenums = new ArrayList();
                    tmpenums.AddRange(enums);
                    tmpenums.Add(new EnumFolderDefinition(tbFolderName.Text, cbFolderTable.SelectedItem.ToString(), 
                        cbFolderDisplay.SelectedItem.ToString(), cbFolderValue.SelectedValue.ToString()));
                    enums = (EnumFolderDefinition[])tmpenums.ToArray(typeof(EnumFolderDefinition));
                }
            }
            else if (currentIndex < folders.Length)
            {
                if (tbFolderName.Text == null || tbFolderName.Text == "")
                {
                    MessageBox.Show("Missing Value Error: " + 
                        "\nFolder Name cannot be empty", "Error");
                    return;
                }
                if (cbFolderTable.SelectedItem == null)
                {
                    MessageBox.Show("Missing Value Error: " +
                        "\nTable cannot be empty", "Error");
                    return;
                }
                if (cbFolderDisplay.Enabled && cbFolderDisplay.SelectedItem == null)
                {
                    MessageBox.Show("Missing Value Error: " +
                        "\nFolder Display cannot be empty", "Error");
                    return;
                }
                if (cbFolderValue.Enabled && cbFolderValue.SelectedItem == null)
                {
                    MessageBox.Show("Missing Value Error: " +
                        "\nFolder Value cannot be empty", "Error");
                    return;
                }
                if (cbFolderLevel.SelectedIndex == -1)
                {
                    MessageBox.Show("Missing Value Error: " +
                        "\nFolder Level cannot be empty", "Error");
                    return;
                }

                folders[currentIndex].Name = tbFolderName.Text;
                folders[currentIndex].TableName = cbFolderTable.SelectedItem.ToString();
                switch (cbFolderLevel.SelectedIndex)
                {
                    case 0:
                        folders[currentIndex].Level = FolderLevel.One;
                        break;
                    case 1:
                        folders[currentIndex].Level = FolderLevel.Two;
                        break;
                    case 2:
                        folders[currentIndex].Level = FolderLevel.Three;
                        break;
                    case 3:
                        folders[currentIndex].Level = FolderLevel.Four;
                        return;
                }
                
                if (cbFolderDisplay.SelectedItem.ToString() == "Expression...")
                    folders[currentIndex].DisplayExp = "Eval(" + tbFolderDisplayExp.Text + ")";
                else
                    folders[currentIndex].DisplayExp = cbFolderDisplay.SelectedItem.ToString();

                if (cbFolderValue.SelectedItem.ToString() == "Expression...")
                    folders[currentIndex].ValueExp = "Eval(" + tbFolderValueExp.Text + ")";
                else
                    folders[currentIndex].ValueExp = cbFolderValue.SelectedItem.ToString();
            }
            else if (currentIndex < folders.Length + enums.Length)
            {
                enums[currentIndex - folders.Length].Name = tbFolderName.Text;
                enums[currentIndex - folders.Length].TableName = cbFolderTable.SelectedItem.ToString();
            }
            Designer.FolderEngine.SetFolderDefinitions(folders);
            Designer.FolderEngine.SetEnumFolderDefinition(enums);
            Designer.FolderEngine.SaveModelFile();
        }

        private void tsbCancelFolder_Click(object sender, EventArgs e)
        {
            folders = Designer.FolderEngine.GetFolderDefinitions();
            enums = Designer.FolderEngine.GetEnumFolderDefinitions();

            RefreshFolders();
            ResetProperties();
        }
        #endregion

        #region SubFolder Event Handlers
        private void tabControl1_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (!tabControl1.SelectedTab.Equals(tpSubFolders))
                return;
            if (currentIndex == -1)
            {
                tabControl1.SelectedTab = tpProperties;
                MessageBox.Show("A folders must be selected before subfolders can be viewed.", "Access Error");
                return;
            }

            if (currentIndex < folders.Length)
            {
                if (folders[currentIndex].Level == FolderLevel.Four)
                {
                    tabControl1.SelectedTab = tpProperties;
                    MessageBox.Show("Subfolders are not available for level 4 folders.", "Access Error");
                    return;
                }

                RefreshSubFolders();
            }
            else if (currentIndex < folders.Length + enums.Length)
            {
                tabControl1.SelectedTab = tpProperties;
                MessageBox.Show("Subfolders are not available for enums.", "Access Error");
                return;
            }
        }

        private void lvSubFolders_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (lvSubFolders.SelectedItems.Count != 1)
            {
                currentSF = null;
                return;
            }

            cbSfName.Enabled = true;
            cbSfColumn.Enabled = true;
            cbSfForeignCol.Enabled = true;

            tsbCancelSubFolder.Enabled = true;
            tsbSaveSubFolder.Enabled = true;

            currentSF = folders[currentIndex].GetSubfolderByName(lvSubFolders.SelectedItems[0].Text);

            cbSfName.SelectedItem = currentSF.Name;
            cbSfColumn.SelectedItem = currentSF.Column;
            cbSfForeignCol.SelectedItem = currentSF.ForeignColumn;
        }

        private void cbSfName_SelectedIndexChanged(object sender, EventArgs e)
        {
            cbSfColumn.Items.Clear();

            TableDefinition seltable = null;
            foreach (FolderDefinition fdef in folders)
            {
                if (fdef.Name.ToUpper().Equals(cbSfName.Text.ToUpper()))
                    seltable = Designer.DatabaseEngine.GetTableByName(fdef.TableName);
            }

            if (seltable == null)
                return;
            cbSfColumn.Items.AddRange(seltable.GetColumnNames());
        }

        private void tsbAddSubFolder_Click(object sender, EventArgs e)
        {
            cbSfName.Enabled = true;
            cbSfColumn.Enabled = true;
            cbSfForeignCol.Enabled = true;

            tsbCancelSubFolder.Enabled = true;
            tsbSaveSubFolder.Enabled = true;

            cbSfName.SelectedIndex = -1;
            cbSfColumn.Items.Clear();
            cbSfForeignCol.SelectedIndex = -1;

            currentSF = null;
        }
        private void tsbDeleteSubFolder_Click(object sender, EventArgs e)
        {
            if (lvSubFolders.SelectedIndices.Count != 1)
                return;

            folders[currentIndex].RemoveSubFolderByName(lvSubFolders.SelectedItems[0].Text);
            RefreshSubFolders();
        } 
        private void tsbCancelSubFolder_Click(object sender, EventArgs e)
        {
            RefreshSubFolders();
        }
        private void tsbSaveSubFolder_Click(object sender, EventArgs e)
        {
            if (cbSfName.Text == "" || cbSfColumn.Text == "" || cbSfForeignCol.Text == "")
            {
                MessageBox.Show("Required field is empty", "Error");
                return;
            }
            if (currentSF == null)
            {
                if (folders[currentIndex].GetSubfolderByName(cbSfName.Text) == null)
                {
                    folders[currentIndex].AddSubFolder(new SubFolderDefinition(
                        cbSfName.Text, cbSfColumn.Text, cbSfForeignCol.Text, null));
                }
                else
                {
                    MessageBox.Show("SubFolder already exists: " + 
                        "\nMultiple subfolders cannot exist for the same folder.", "Error");
                }
            }
            else
            {
                folders[currentIndex].ReplaceSubFolderByName(currentSF.Name, new SubFolderDefinition(
                    cbSfName.Text, cbSfColumn.Text, cbSfForeignCol.Text, null));
            }
            RefreshSubFolders();
        }
        #endregion
    }
}
